package models;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import models.msgs.GetCardsToExchange;
import models.msgs.GiveCards;
import models.msgs.GiveCoins;
import models.msgs.QuitMessage;
import models.msgs.RetrieveBet;
import models.msgs.StringMessage;
import play.Logger;
import play.libs.F.Callback;
import play.libs.F.Callback0;
import play.libs.Json;
import play.mvc.WebSocket;
import akka.actor.ActorRef;
import akka.actor.UntypedActor;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class HumanStrategy extends UntypedActor
{
    public enum WaitFor
    {
    	Cards, Bet, Nothing
    }
	
	protected WebSocket.In<JsonNode>  in;
    protected WebSocket.Out<JsonNode> out;
    protected final ActorRef table;
    
    protected WaitFor waitsFor;
    protected ActorRef sender;
    
    protected List<Card> cards;
    protected int coins;
    
    public HumanStrategy(WebSocket.In<JsonNode> _in,
            WebSocket.Out<JsonNode> _out, ActorRef _table)
    {
        in = _in;
        out = _out;
        table = _table;
        waitsFor = WaitFor.Nothing;

        in.onClose(new Callback0()
        {
            @Override
            public void invoke()
            {
                table.tell(new QuitMessage(), getSelf());
            }
        });
        
        in.onMessage(new Callback<JsonNode>()
		{
			@Override
            public void invoke(JsonNode event)
            {
				try
                {
                	if(waitsFor == WaitFor.Cards)
                	{
                		getCardsToExchange(event);
                	}
                	else if(waitsFor == WaitFor.Bet)
                	{
                		retrieveBet(event);
                	}
                }
                catch (Exception e)
                {
                    Logger.error("invokeError");
                }
                
            }
        });
    }

    @Override
    public void onReceive(Object msg) throws Exception
    {
    	if(msg instanceof StringMessage)
    	{		
    		ObjectNode event = Json.newObject();
			event.put("message", ((StringMessage) msg).message);
			
			out.write(event);
    	}
    	else if(msg instanceof RetrieveBet)
    	{
    		waitsFor = WaitFor.Bet;
    		sender = getSender();
    		
    		ObjectNode event = Json.newObject();
			event.put("message", "Podaj zakład");
			
			out.write(event);
    	}
    	else if(msg instanceof GetCardsToExchange)
    	{
    		waitsFor = WaitFor.Cards;
    		sender = getSender();
    		
    		ObjectNode event = Json.newObject();
			event.put("message", "Podaj karty");
			
			out.write(event);
    	}
    	else if(msg instanceof GiveCards)
    	{
    		giveCards(((GiveCards) msg).cards);
    	}
    	else if (msg instanceof GiveCoins)
    	{
    		giveCoins(((GiveCoins) msg).coins);
    	}
    	else
    	{
    		unhandled(msg);
    	}
    }  
    
	private void getCardsToExchange(JsonNode event) {
		List<String> cardsString = new ArrayList<String>(Arrays.asList(event.get("nr").asText().split(" , ")));
		
		List<Card> cardsToExchange = new LinkedList<Card>();
		
		for(String cardNo: cardsString)
		{
			int cardNumber = Integer.parseInt(cardNo);
			if(cardNumber < 1 || cardNumber > 5)return;
			cardsToExchange.add(cards.get(cardNumber-1));
		}
		
		if(cardsToExchange.size() > 4)return;
		
		sender.tell(cardsToExchange, getSelf());
		waitsFor = WaitFor.Nothing;
		sender = null;
	}

	private void giveCards(List<Card> _cards) {
		cards = _cards;
		
		ObjectNode event = Json.newObject();
		String cardsString = "";
		for(Card card: _cards)
		{
			cardsString += card.toString() + ", ";
		}
		event.put("message", "Twoje karty: " + cardsString);
		out.write(event);
	}
	
	private void giveCoins(int _coins)
	{
		coins = _coins;
		
		ObjectNode event = Json.newObject();
		event.put("message", "Twoje ilość monet: " + Integer.toString(coins));
		out.write(event);
	}
	
	private void retrieveBet(JsonNode event) {
		int bet = event.get("nr").asInt();
		
		sender.tell(bet, getSelf());
		waitsFor = WaitFor.Nothing;
		sender = null;
	}  
            
}

